package network

import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"
	"github.com/chenwbyx/leafserver/server/common"
	"github.com/chenwbyx/leafserver/server/msg/client"
	"github.com/golang/protobuf/proto"
	"github.com/name5566/leaf/log"
	"golang.org/x/net/websocket"
	"io"
	"net"
	"strings"
	"sync"
)

type WebSession struct {
	sockid        uint64
	conn          *websocket.Conn
	writeChan     chan interface{}
	OnClose       func(common.ISession)
	stream        PacketStream
	userItem      interface{}
	endSync       sync.WaitGroup //协程结束
	needStopWrite bool           //是否需要主动断开写协程
	isDone        bool           //session是否已经关闭
	bindData      interface{}
	sendList      *PacketList //将发包改为发送列表

}

// 发包
func (self *WebSession) Send(mainId uint16, subId uint16, data []byte) error {
	pkt := MakePacket(mainId, subId, data)
	if self.isDone {
		return errors.New("session has done")
	}
	self.sendList.Add(pkt)

	return nil
}

func (self *WebSession) IsClosed() bool {
	return self.isDone
}

// 断开
func (self *WebSession) Close(closeType common.CloseType) {
	if !self.isDone {
		self.isDone = true
		//通知关闭写协程
		self.sendList.Close()
	}

}

// 标示ID
func (self *WebSession) ID() uint64 {
	return self.sockid
}

func (self *WebSession) BindSessionData(info interface{}) {
	self.userItem = info
}

func (self *WebSession) GetSessionData() interface{} {
	return self.userItem
}

func (self *WebSession) GetSessionString() string {
	return ""
}

func (self *WebSession) GetSessionInfo() *common.SessionInfo {
	if self.userItem == nil {
		return nil
	}
	switch info := self.userItem.(type) {
	case *common.SessionInfo:
		return info
	}
	return nil
}

func (self *WebSession) GetRemoteAddr() string {
	remoteAddr := self.conn.Request().RemoteAddr
	if strings.Contains(remoteAddr, ":") {
		ip, _, err := net.SplitHostPort(remoteAddr)
		if err != nil {
			fmt.Println("解析IP地址出错:", err)
		}
		remoteAddr = ip
	}

	if ip := self.conn.Request().Header.Get("X-Real-IP"); ip != "" {
		remoteAddr = ip
	} else if ip := self.conn.Request().Header.Get("X-Forwarded-For"); ip != "" {
		remoteAddr = strings.Split(ip, ", ")[0]
	}

	log.Debug("获得真实IP:", remoteAddr)
	return remoteAddr
}

func (self *WebSession) sendThread() {
	var sendList []*Packet
	for true {
		sendList = sendList[0:0]

		//复制出队列
		packetList := self.sendList.BeginPick()
		sendList = append(sendList, packetList...)

		self.sendList.EndPick()
		willExit := false
		//写队列
		for _, p := range sendList {
			if p.MainId == InvliadPacketMainID {
				goto exitSendLoop
			} else if err := self.stream.Write(p); err != nil {
				willExit = true
				log.Debug("WebSession 发送数据错误:%v", err)
				break
			}
		}

		if willExit {
			goto exitSendLoop
		}
	}

exitSendLoop:
	self.isDone = true
	self.needStopWrite = false
	self.stream.Close()

	self.endSync.Done()
}

func (self *WebSession) recvThread() {
	for {
		err := common.SafeCall(func(args ...interface{}) error {
			se, ok := args[0].(*WebSession)
			//从Socket读取封包
			if ok {
				pk, err := se.stream.Read()
				if err != nil {
					if err == io.EOF {
						log.Error("WebSession-对端关闭")
					} else {
						log.Error("WebSession-错误", err)
					}
					return err
				}
				//if pk.MainId == uint16(message.ClientCmd_SubCmd_Main_Code) && pk.SubId == uint16(message.ClientCmd_SubGateCmd_ClientAlive) {
				//	self.Send(uint16(message.ClientCmd_SubCmd_Main_Code), uint16(message.ClientCmd_SubGateCmd_ClientAlive), nil)
				//} else {
				//	ret := se.iattemper.OnEventTCPNetworkRead(pk.MainId, pk.SubId, pk.Data, se)
				//	if !ret {
				str := fmt.Sprintf("逻辑层处理错误 %d %d", pk.MainId, pk.SubId)
				return errors.New(str)
				//	}
				//}
			}
			return nil
		}, self)

		if err != nil {
			if err != io.EOF {
				log.Error("WebSession:%v", err)
			}
			break
		}
	}

	self.isDone = true
	if self.needStopWrite {
		self.sendList.Close()
	}

	//通知接收线程ok
	self.endSync.Done()
}

func (self *WebSession) Recv(uint16, uint16, []byte) bool {
	return false
}

func (self *WebSession) existThread() {
	//等待2个任务结束
	self.endSync.Wait()
	common.SafeCall(func(args ...interface{}) error {
		//se := args[0].(*WebSession)
		//se.iattemper.OnEventTCPNetworkShut(se)
		return nil
	}, self)

	if self.OnClose != nil {
		self.OnClose(self)
	}
}

func (self *WebSession) StartSession() {
	//布置接收和发送2个任务
	self.endSync.Add(2)

	//退出线程
	go self.existThread()

	//接收线程
	go self.recvThread()

	//发送线程
	self.sendThread()
}

func (self *WebSession) SetBindData(data interface{}) {
	self.bindData = data
}

func (self *WebSession) GetBindData() interface{} {
	return self.bindData
}

func (self *WebSession) SendPbMessage(mainId uint16, subId uint16, pb proto.Message) error {
	data, err := proto.Marshal(pb)
	if err != nil {
		log.Error("%v", err)
		return err
	}
	return self.Send(mainId, subId, data)
}

func (self *WebSession) SendGobMessage(mainId uint16, subId uint16, e interface{}) error {
	var netdata bytes.Buffer
	enc := gob.NewEncoder(&netdata)
	if err := enc.Encode(e); err != nil {
		log.Error("%v", err)
		return err
	}
	return self.Send(mainId, subId, netdata.Bytes())
}

func (self *WebSession) SendMessage(code client.ClientCmd, pb proto.Message) error {
	data, err := proto.Marshal(pb)
	if err != nil {
		log.Error("%v", err)
		return err
	}
	return self.Send(0, uint16(code), data)
}

func (self *WebSession) SendPubMessage(code client.ClientCmd, e interface{}) error {
	var netdata bytes.Buffer
	enc := gob.NewEncoder(&netdata)
	if err := enc.Encode(e); err != nil {
		log.Error("%v", err)
		return err
	}
	return self.Send(0, uint16(code), netdata.Bytes())
}

func NewWebSession(sockid uint64, tcpcon *websocket.Conn, isEncrypt bool) *WebSession {
	self := &WebSession{
		conn:          tcpcon,
		sockid:        sockid,
		isDone:        false,
		needStopWrite: true,
		bindData:      nil,
		sendList:      NewPacketList(),
		//log:           common.NewLogger(),
	}
	self.stream = NewWebStream(self.conn, isEncrypt)
	return self
}
